package com.york.utils.util;

import com.alibaba.fastjson.JSONObject;
import com.york.utils.client.HttpsClient;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * http工具类
 *
 * @author yangboxiong
 */
public class HttpUtils {
    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
    private int CONN_TIMEOUT = 10000;
    private int TIMEOUT = 20000;
    private String CHARSET = "UTF-8";

    // header 常量定义
    private static final String DEFAULT_ENCODING = "UTF-8";
    private static final boolean DEFAULT_NOCACHE = true;
    // Content Type 常量定义
    public static final String TEXT_TYPE = "text/plain";
    public static final String JSON_TYPE = "application/json";
    public static final String XML_TYPE = "text/xml";
    public static final String XML_TYPE_UTF = "text/xml;charset=UTF-8";
    public static final String HTML_TYPE = "text/html";
    public static final String JS_TYPE = "text/javascript";
    public static final String EXCEL_TYPE = "application/vnd.ms-excel";
    public static final String POST_DEFAULT_TYPE = "application/x-www-form-urlencoded";
    public static final String POST_DEFAULT_TYPE_UTF = "application/x-www-form-urlencoded; charset=utf-8";
    public static final String POST_DEFAULT_TYPE_UTF_2 = "application/x-www-form-urlencoded;charset=utf-8";
    public static final String JSON_TYPE_UTF = "application/json; charset=utf-8";
    public static int PAGE_NUMERIC = 20;
    public static final String POST_FORM_DATA = "form-data";
    //提交方式
    public static final String POST = "POST";
    public static final String GET = "GET";

    public HttpUtils(int CONN_TIMEOUT, int TIMEOUT, String CHARSET) {
        super();
        this.CONN_TIMEOUT = CONN_TIMEOUT;
        this.TIMEOUT = TIMEOUT;
        this.CHARSET = CHARSET;
    }

    public HttpUtils(String CHARSET) {
        super();
        this.CHARSET = CHARSET;
    }

    public HttpUtils() {
    }

    /**
     * 获取get请求
     *
     * @param url 地址
     * @return
     * @throws Exception
     */
    public String httpGet(String url) throws Exception {
        CloseableHttpClient httpCilent2 = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(CONN_TIMEOUT)   //设置连接超时时间
                .setConnectionRequestTimeout(CONN_TIMEOUT) // 设置请求超时时间
                .setSocketTimeout(TIMEOUT)
                .setRedirectsEnabled(true)//默认允许自动重定向
                .build();
        HttpGet httpGet2 = new HttpGet(url);
        httpGet2.setConfig(requestConfig);
        String srtResult = "";
        try {
            HttpResponse httpResponse = httpCilent2.execute(httpGet2);
            if (httpResponse.getStatusLine().getStatusCode() == 200) {
                srtResult = EntityUtils.toString(httpResponse.getEntity());//获得返回的结果
            } else if (httpResponse.getStatusLine().getStatusCode() == 400) {
                throw new Exception("请求异常:400");
            } else if (httpResponse.getStatusLine().getStatusCode() == 500) {
                throw new Exception("请求异常:500");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpCilent2.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        log.info("---->请求返回：" + srtResult);
        return srtResult;
    }

    /**
     * post 参数提交
     *
     * @param url     提交地址
     * @param params  post参数
     * @param header  header
     * @param charset 编码
     * @return
     * @throws Exception
     */
    public String httpPost(String url, Map<String, Object> params, Map<String, String> header, String charset) throws Exception {
        List<BasicNameValuePair> paramsList = new ArrayList();
        log.info("提交-->" + url);
        for (String key : params.keySet()) {
            paramsList.add(new BasicNameValuePair(key, StringUtil.ifEmptyThen(params.get(key), "")));
            log.info("提交参数-->" + key + ":" + params.get(key));
        }
        CloseableHttpClient http = null;
        if (url.startsWith("https:")) {
            http = HttpsClient.createSSLClientDefault();
        } else {
            http = HttpClients.createDefault();
        }
        if (StringUtil.isBlank(charset)) {
            charset = CHARSET;
        }
        return postHeader(url, http, paramsList, header, "", charset, null);
    }

    /**
     * 流提交
     *
     * @param url       提交地址
     * @param streamStr 流字符串
     * @param header    header
     * @param charset   编码
     * @return
     * @throws Exception
     */
    public String httpStream(String url, String streamStr, Map<String, String> header, String charset) throws Exception {
        log.info("提交-->" + url);
        log.info("提交参数-->" + streamStr);
        CloseableHttpClient http = null;
        if (url.startsWith("https:")) {
            http = HttpsClient.createSSLClientDefault();
        } else {
            http = HttpClients.createDefault();
        }
        if (StringUtil.isBlank(charset)) {
            charset = CHARSET;
        }
        return postHeader(url, http, null, header, streamStr, charset, null);
    }

    /**
     * post 参数提交
     *
     * @param url     提交地址
     * @param params  post参数
     * @param header  header
     * @param charset 编码
     * @return
     * @throws Exception
     */
    public String httpMultipart(String url, Map<String, Object> params, Map<String, String> header, String charset) throws Exception {
        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
        ContentType contentType = ContentType.create("multipart/form-data", Charset.forName(charset));
        log.info("提交-->" + url);
        for (String key : params.keySet()) {
            entityBuilder.addPart(key, new StringBody(StringUtil.ifEmptyThen(params.get(key), ""), contentType));
            log.info("提交参数-->" + key + ":" + params.get(key));
        }
        CloseableHttpClient http = null;
        if (url.startsWith("https:")) {
            http = HttpsClient.createSSLClientDefault();
        } else {
            http = HttpClients.createDefault();
        }
        if (StringUtil.isBlank(charset)) {
            charset = CHARSET;
        }
        return postHeader(url, http, null, header, "", charset, entityBuilder);
    }

    /**
     * @param url        请求地址
     * @param http
     * @param paramsList 请求参数
     * @param header     请求头
     * @param streamStr
     * @param charset    编码
     * @return
     * @throws Exception
     */
    private String postHeader(String url, CloseableHttpClient http, List<BasicNameValuePair> paramsList, Map<String, String> header, String streamStr, String charset, MultipartEntityBuilder entityBuilder) throws Exception {
        StringBuilder returnBuffer = new StringBuilder();
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;

        if (header != null) {
            for (String key : header.keySet()) {
                String val = header.get(key);
                if (!StringUtil.isBlank()) {
                    httpPost.setHeader(key, val);
                }
            }
        }

        if (!StringUtil.isBlank(streamStr)) {
            EntityBuilder eb = EntityBuilder.create();
            eb.setBinary(streamStr.getBytes(charset));
            httpPost.setEntity(eb.build());
        }
        if (paramsList != null) {
            httpPost.setEntity(new UrlEncodedFormEntity(paramsList, charset));
        }
        if (entityBuilder != null) {
            httpPost.setEntity(entityBuilder.build());
        }

        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(getTIMEOUT()).setConnectTimeout(getCONN_TIMEOUT()).build();
        httpPost.setConfig(requestConfig);
        response = http.execute(httpPost);

        HttpEntity httpEntity = response.getEntity();
        if (httpEntity != null) {
            httpEntity = new BufferedHttpEntity(httpEntity);
            InputStream is = httpEntity.getContent();
            BufferedReader br = new BufferedReader(new InputStreamReader(is, getCHARSET()));
            String str;
            while ((str = br.readLine()) != null) {
                returnBuffer.append(str);
            }
            is.close();
        }
        return returnBuffer.toString();

    }

    /**
     * 从request数据流中读取字符串
     *
     * @param request request
     * @return
     */
    public static String getPostStrFromStream(HttpServletRequest request, String charset) {
        StringBuffer buffer = new StringBuffer();
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        if (StringUtil.isBlank(charset)) {
            charset = DEFAULT_ENCODING;
        }
        try {
            inputStream = request.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream, charset);
            bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
        } catch (UnsupportedEncodingException e) {
            // SysLogger.error(class, "请求字符集不支持，获取请求数据出错");
            e.printStackTrace();
        } catch (IOException e) {
            // SysLogger.error(class, "IO异常，获取请求出错");
            e.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                }
            }
            if (inputStreamReader != null) {
                try {
                    inputStreamReader.close();
                } catch (IOException e) {
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                }
            }
        }

        return buffer.toString();
    }

    /**
     * 获取请求参数 JSON
     *
     * @param request 请求消息
     * @param charset 字符编码
     * @return
     */
    public static JSONObject getRequestParamJson(HttpServletRequest request, String charset) {
        String contentType = StringUtil.ifEmptyThen(request.getContentType(), "");
        String method = StringUtil.ifEmptyThen(request.getMethod(), "");

        JSONObject resJsonObject = null;
        String reqParam = "";
        try {

            if (StringUtil.isBlank(charset)) {
                charset = DEFAULT_ENCODING;
            }
            if (method.equalsIgnoreCase("get") || ((method.equalsIgnoreCase("post") && !StringUtil.isBlank(contentType)))) {
                if (method.equalsIgnoreCase(methods[0]) || contentType.contains("application/x-www-form-urlencoded")) {
                    Map parameterMap = request.getParameterMap();
                    resJsonObject = StringUtil.getRequestMapValue(parameterMap);
                } else if (method.equalsIgnoreCase(methods[1]) && contentType.contains("application/json")) {
                    resJsonObject = JSONObject.parseObject(getPostStrFromStream(request, charset));
                } else if (method.equalsIgnoreCase(methods[1]) && contentType.contains("xml")) {
                    reqParam = getPostStrFromStream(request, charset);
                    if (!StringUtil.isBlank(reqParam)) {

                    }
                } else if (contentType.contains("form-data")) {

                }
            }
        } catch (Exception e) {
            log.error("----->解析request数据异常:{}", e.getMessage());
            e.printStackTrace();
        }
        return resJsonObject;
    }

    public int getCONN_TIMEOUT() {
        return CONN_TIMEOUT;
    }

    public int getTIMEOUT() {
        return TIMEOUT;
    }

    public String getCHARSET() {
        return CHARSET;
    }

    public static final String[] methods = {
            "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"
    };
}

